package fhq.hcmute.qrcode.desktop.image;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import fhq.hcmute.qrcode.QRCode;
import fhq.hcmute.qrcode.common.BinaryImage;
import fhq.hcmute.qrcode.common.BitMatrix;

/**
 * @author: Hien Nguyen Le
 * @Email: nglehien@gmail.com
 */
public class BufferImageUtil {

	public static BinaryImage parse(BufferedImage srcImage) {
		BufferedImage image = new BufferedImage(srcImage.getWidth(),
				srcImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
		image.getGraphics().drawImage(srcImage, 0, 0, null);
		int width = image.getWidth();
		int height = image.getHeight();
		Raster raster = image.getData();
		DataBuffer buffer = raster.getDataBuffer();
		DataBufferByte byteBuffer = (DataBufferByte) buffer;
		byte[] srcData = byteBuffer.getData(0);
		return new BinaryImage(width, height, srcData);
	}

	public static BinaryImage parse(String file) throws IOException {
		BufferedImage srcImage = ImageIO.read(new File(file));
		return parse(srcImage);
	}

	public static BufferedImage parse(BinaryImage binaryImage) {
		int height = binaryImage.getHeight();
		int width = binaryImage.getWidth();
		BufferedImage bi = new BufferedImage(width, height,
				BufferedImage.TYPE_3BYTE_BGR);
		Graphics2D g = (Graphics2D) bi.getGraphics();
		g.fillRect(0, 0, width, height);
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				if (binaryImage.getPixel(i, j)) {
					g.setColor(Color.BLACK);
					g.fillRect(j, i, 1, 1);
				}
			}
		}
		g.dispose();
		return bi;
	}

	public static class Builder {
		private int dotSize = 5;
		private int boderOffset = dotSize * 5;
		private Color dotColor = Color.BLACK;
		private Color backgroundColor = Color.WHITE;
		private static Builder instance;
		private QRCode qrCode;
		private String title;

		private Builder() {

		}

		public Builder(QRCode qrCode) {
			instance = new Builder();
			instance.qrCode = qrCode;
		}

		public Builder setDotSize(int size) {
			instance.dotSize = size;
			instance.boderOffset = instance.dotSize * 5;
			return instance;
		}

		public Builder setDotColor(Color color) {
			instance.dotColor = color;
			return instance;
		}

		public Builder setTitle(String title) {
			instance.title = title;
			return instance;
		}

		public boolean saveToFile(String filename) {
			File f = new File(filename);
			return saveToFile(f);
		}

		public boolean saveToFile(File file2Save) {
			BufferedImage img = getBufferedImage(instance);
			try {
				ImageIO.write(img, "PNG", file2Save);
				return true;
			} catch (IOException e) {
				e.printStackTrace();
			}
			return false;
		}

		private BufferedImage getBufferedImage(Builder instance) {
			this.qrCode = instance.qrCode;
			this.title = instance.title;
			this.dotSize = instance.dotSize;
			this.boderOffset = instance.boderOffset;
			this.dotColor = instance.dotColor;
			int[][] arrayByte = qrCode.getDataMatrix().getRawValues();
			int X = arrayByte.length;
			int Y = X;
			int subHeight = 0;
			if (title != null) {
				subHeight = 30;
			}
			BufferedImage bi = new BufferedImage(dotSize * X + boderOffset,
					dotSize * Y + boderOffset + subHeight,
					BufferedImage.TYPE_3BYTE_BGR);
			Graphics2D g = (Graphics2D) bi.getGraphics();
			g.setColor(backgroundColor);
			g.fillRect(0, 0, dotSize * X + boderOffset, dotSize * Y
					+ boderOffset + subHeight);
			int x, y;
			for (int i = 0; i < X; i++) {
				for (int j = 0; j < Y; j++) {
					x = i * dotSize;
					y = j * dotSize;
					if (arrayByte[i][j] == BitMatrix.TRUE) {
						g.setColor(dotColor);
						g.fillRect(y + boderOffset / 2, x + boderOffset / 2,
								dotSize, dotSize);
					}
				}
			}
			g.setColor(Color.RED);
			if (title != null) {
				g.setFont(new Font("Arial", Font.BOLD, 13));
				g.drawString(title, 5, Y * dotSize + 35);
			}
			g.dispose();
			return bi;
		}
	}

}
